import { computed, defineComponent, h, markRaw, reactive, watch } from 'vue'
import DataNode from '../../ItemNode/DataNode'
import {
  ElButton,
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElOption,
  ElPopover,
  ElSelect,
  ElSwitch,
  ElText,
  ElTree
} from 'element-plus'
import classes from '../../ItemNode/ItemNode.module.css'
import { generateRule } from '../../utils'
import { Delete, Edit } from '@element-plus/icons-vue'
import { state } from '../../store/store.js'
import CodeEditor from '../../panel/CodeEditor.vue'
import Tip from '../../panel/Tip.vue'

export default class NSelect extends DataNode {
  isNSelect = true
  isFormNode = true

  constructor(node?: NSelect) {
    super(node)

    const _self = this

    this.watchStateOptions.push({
      value: 'initData',
      label: '刷新数据'
    })

    if (!node) {
      this.path = './components/NSelect/NSelect.tsx'
      this.name = '选择器'

      this.props.field = `${NSelect.name.replace(/^N(\w)/, (match, p1) => p1.toLowerCase())}_${this.uuid.split('-').at(0)}`
      this.props.value = ''
      this.props.options = [
        {
          id: 1,
          label: '默认选项1',
          value: 1
        },
        {
          id: 2,
          label: '默认选项2',
          value: 2
        }
      ]
      this.props.dataUrl = ''
      this.props.dataFn = `function () {
  return [
    {
      id: 1,
      label: '默认选项1',
      value: 1
    },
    {
      id: 2,
      label: '默认选项2',
      value: 2
    }
  ]
}
`
      this.props.label = ''
      this.props.placeholder = '请选择'
      this.props.multiple = false
      this.props.clearable = false
      this.props.ruleMessage = '请正确输入'
      this.props.ruleType = 'none'
      this.props.changeFn = `function (value) {\n  value\n}`
      this.props.filterable = false
      this.props.remote = false
      this.props.remoteFn = `function (query) {\n    _self.props.dataUrl = \`/\${query}\`\n}`
    }

    const rulesOptions = reactive([
      {
        label: '无验证',
        value: 'none'
      },
      {
        label: '默认验证',
        value: 'default'
      }
    ])

    const pComponent = this.component
    this.component = markRaw(
      defineComponent(
        (props) => {
          const rule = computed(() => generateRule(this.props.ruleType, this.props.ruleMessage))

          watch(
            () => this.props.data,
            () => {
              if (this.props.dataFnable) this.props.options = this.props.data ?? []
            },
            { immediate: true }
          )

          const onChange = (value) => {
            if (state) eval(`(${this.props.changeFn})`)(value)
          }

          onChange(this.props.value)

          const remoteMethod = (query) => {
            if (_self) eval(`(${this.props.remoteFn})`)(query)
          }

          return () => (
            <pComponent>
              <ElFormItem label={this.props.label} prop={this.props.field} rules={rule.value}>
                <ElSelect
                  placeholder={this.props.placeholder}
                  multiple={this.props.multiple}
                  clearable={this.props.clearable}
                  filterable={this.props.filterable}
                  remote={this.props.remote}
                  remoteMethod={remoteMethod}
                  teleported={false}
                  modelValue={this.props.value}
                  onUpdate:modelValue={(value) => (this.props.value = value)}
                  onChange={onChange}
                >
                  {this.props.options.map((option) => (
                    <ElOption key={option.id} label={option.label} value={option.value}></ElOption>
                  ))}
                </ElSelect>
              </ElFormItem>
            </pComponent>
          )
        },
        {
          name: 'NSelect'
        }
      )
    )

    const pView = this.view
    this.view = markRaw(
      defineComponent((props) => {
        return () => (
          <pView>
            <this.component style={{ width: '100px', transform: 'scale(0.8)' }}></this.component>
          </pView>
        )
      })
    )

    const pParams = this.params
    this.params = markRaw(
      defineComponent(() => {
        return () => (
          <pParams>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                字段
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.field} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                标签
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.label} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                选项
              </ElText>
              <div class={classes['params-item-content']}>
                <ElButton
                  type="primary"
                  size="small"
                  onClick={() => {
                    const option = {
                      id: Math.random(),
                      label: '新选项',
                      value: '值'
                    }
                    this.props.options.push(option)
                  }}
                >
                  + 添加选项
                </ElButton>
                <ElTree
                  data={this.props.options}
                  node-key="id"
                  default-expand-all
                  expand-on-click-node={false}
                >
                  {{
                    default: ({ node, data }) => {
                      return (
                        <span
                          style={{
                            flex: '1',
                            display: 'flex',
                            justifyContent: 'space-between'
                          }}
                        >
                          <span>{data.label}</span>
                          <span>
                            <ElPopover
                              width={180}
                              trigger="click"
                              teleported={false}
                              placement="left"
                            >
                              {{
                                reference: () => (
                                  <ElIcon color="var(--el-color-primary)">
                                    <Edit></Edit>
                                  </ElIcon>
                                ),
                                default: () => {
                                  return (
                                    <>
                                      <ElForm label-width="50px">
                                        <ElFormItem label="标签">
                                          <ElInput v-model={data.label}></ElInput>
                                        </ElFormItem>
                                        <ElFormItem label="值">
                                          <ElInput v-model={data.value}></ElInput>
                                        </ElFormItem>
                                      </ElForm>
                                    </>
                                  )
                                }
                              }}
                            </ElPopover>
                            {h(
                              ElIcon,
                              {
                                color: 'var(--el-color-danger)',
                                onClick: () => {
                                  const parent = node.parent
                                  const children = parent.data.children || parent.data
                                  const index = children.findIndex((d) => d.value === data.value)
                                  children.splice(index, 1)
                                }
                              },
                              {
                                default: () => <Delete></Delete>
                              }
                            )}
                          </span>
                        </span>
                      )
                    }
                  }}
                </ElTree>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                占位文本
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.placeholder} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                多选
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch
                  modelValue={this.props.multiple}
                  onUpdate:modelValue={(v) => {
                    this.props.multiple = v
                    if (v) this.props.value = []
                    else this.props.value = '' // null切换有问题
                  }}
                  size="small"
                ></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                可清空
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.clearable} size="small"></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                可筛选
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.filterable} size="small"></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                远程搜索
                <Tip content={'可访问的变量：节点自身_self；query：输入值'}></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.remote} size="small"></ElSwitch>
                {this.props.remote ? (
                  <CodeEditor
                    modelValue={this.props.remoteFn}
                    onUpdate:modelValue={(v) => (this.props.remoteFn = v || '')}
                  ></CodeEditor>
                ) : null}
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                验证规则
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSelect v-model={this.props.ruleType} size="small" teleported={false}>
                  {() =>
                    rulesOptions.map((item) => (
                      <ElOption key={item.value} label={item.label} value={item.value}></ElOption>
                    ))
                  }
                </ElSelect>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                验证消息
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.ruleMessage} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                值变化处理函数
                <Tip content={'值变化后调用；可访问全局状态变量state，value：组件的值'}></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <CodeEditor
                  modelValue={this.props.changeFn}
                  onUpdate:modelValue={(v) => (this.props.changeFn = v || '')}
                ></CodeEditor>
              </div>
            </div>
          </pParams>
        )
      })
    )
  }

  toVue(): SfcObj {
    const sfcObj = super.toVue()
    const name = sfcObj.name
    const dataVar = sfcObj.dataVar
    const [uuid0, uuid1] = this.uuid.split('-')
    const valueVar = `${name}_${uuid0}_value`
    const optionsVar = `${name}_${uuid0}_options`
    const ruleVar = `${name}_${uuid0}_rule`
    const onChangeVar = `${name}_${uuid0}_onChange`

    const optionsStr = JSON.stringify(this.props.options)
    const ruleStr = JSON.stringify(generateRule(this.props.ruleType, this.props.ruleMessage))

    sfcObj.imports = {
      ...sfcObj.imports,
      vue: {
        ...sfcObj.imports.vue,
        ref: 'ref',
        watch: 'watch'
      },
      ['element-plus']: {
        ElFormItem: 'ElFormItem',
        ElSelect: 'ElSelect',
        ElOption: 'ElOption'
      }
    }

    sfcObj.script = `
${sfcObj.script}
const ${valueVar} = ${this.props.multiple ? 'ref([])' : "ref('')"}
const ${optionsVar} = ref(${optionsStr})
const ${ruleVar} = ref(${ruleStr})

watch(${dataVar}, () => {
  ${optionsVar}.value = ${dataVar}.value ?? []
})

const ${onChangeVar} = (value) => {
  (${this.props.changeFn})(value)
}
${onChangeVar}(${typeof this.props.value == 'string' ? `'${this.props.value}'` : this.props.value})
      `

    sfcObj.template = sfcObj.template.replace(
      '<slot></slot>',
      `
  <ElFormItem label="${this.props.label}" prop="${this.props.field}" :rules="${ruleVar}">
    <ElSelect
      v-model="${valueVar}"
      :multiple="${this.props.multiple}"
      placeholder="${this.props.placeholder}"
      :teleported="false"
      @change="${onChangeVar}"
    >
      <ElOption
        v-for="option of ${optionsVar}"
        :key="option.id"
        :label="option.label"
        :value="option.value"
      ></ElOption>
    </ElSelect>
  </ElFormItem>
       `
    )

    return sfcObj
  }
}
